package com.atguigu.tingshu.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.constant.RabbitConstant;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.UserPaidAlbum;
import com.atguigu.tingshu.model.user.UserPaidTrack;
import com.atguigu.tingshu.user.config.WxConfigurationProperties;
import com.atguigu.tingshu.user.mapper.UserInfoMapper;
import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper;
import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaSigner;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.security.interfaces.RSAPrivateKey;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;


    @Autowired
    private RedisTemplate redisTemplate;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private WxConfigurationProperties wxConfigurationProperties;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RSAPrivateKey rsaPrivateKey;

    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;

    @Autowired
    private UserPaidTrackMapper userPaidTrackMapper;

    /**
     * 微信登录授权
     *
     * @param code
     * @return
     */
    @SneakyThrows
    @Override
    public JSONObject wxLogin(String code) {
        //参数校验
        if (StringUtils.isEmpty(code)) {
            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        }

        //请求参数拼接
        String appId = wxConfigurationProperties.getAppId();
        String appSecret = wxConfigurationProperties.getAppSecret();
        String url = wxConfigurationProperties.getUrl();
        url += "&appid=" + appId + "&secret=" + appSecret + "&js_code=" + code;
        //请求调用微信接口
        ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
        JSONObject jsonObject = JSONObject.parseObject(response.getBody());
        //获取openId
        String openid = jsonObject.getString("openid");

        //查询用户
        UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getWxOpenId, openid));
        if (userInfo == null) {
            //用户不存在,注册用户
            userInfo = new UserInfo();
            userInfo.setWxOpenId(openid);
            userInfo.setNickname("用户xxx");
            userInfo.setIsVip(0);
            userInfo.setVipExpireTime(new Date());
            int i = userInfoMapper.insert(userInfo);
            if (i <= 0) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //发消息给账户模块创建账户
            rabbitTemplate.convertAndSend(RabbitConstant.ACCOUNT_INIT_EXCHANGE,
                    RabbitConstant.ACCOUNT_INIT_ROUTING,
                    //用字符串方式发送消息
                    userInfo.getId() + "",
                    msg -> {
                        //设置消息为持久化消息
                        msg.getMessageProperties().setDeliveryMode(MessageProperties.DEFAULT_DELIVERY_MODE);
                        return msg;
                    });
        }

        //将用户登录的保存到redis(这里保存登录的设备号,防止令牌被盗用),同时防止多端登录,只记录最后一次的登录信息
        Map userInfoMap = new HashMap<>();
        userInfoMap.put("shebeixuleihao", "设备序列号");
        userInfoMap.put("isVip", userInfo.getIsVip());
        userInfoMap.put("vipExpireTime", userInfo.getVipExpireTime());
        redisTemplate.opsForValue().set("User:Login:" + userInfo.getId(), userInfoMap, 2, TimeUnit.HOURS);

        //生成token
        String token = JwtHelper.encode(userInfo.getId().toString(), new RsaSigner(rsaPrivateKey)).getEncoded();
        //返回token
        JSONObject result = new JSONObject();
        result.put("token", token);
        return result;
    }

    /**
     * 获取用户登录信息
     *
     * @param userId
     * @return
     */
    @Override
    public UserInfoVo getUserInfoByUserId(Long userId) {
        return baseMapper.getUserInfoByUserId(userId);
    }

    /**
     * 更新用户信息
     *
     * @param userInfoVo
     */
    @Override
    public void updateUser(UserInfoVo userInfoVo) {
        UserInfo userInfo = new UserInfo();
        //设置用户信息
        userInfo.setId(AuthContextHolder.getUserId());
        userInfo.setNickname(userInfoVo.getNickname());
        userInfo.setAvatarUrl(userInfoVo.getAvatarUrl());

        //更新用户信息
        int i = baseMapper.updateById(userInfo);

        //更新失败
        if (i <= 0) {
            throw new GuiguException(201, "更新用户信息失败");
        }
    }

    /**
     * 查询用户是否购买专辑
     *
     * @param userId
     * @param albumId
     * @return
     */
    @Override
    public Boolean isBuyAlbum(Long userId, Long albumId) {
        return userPaidAlbumMapper.selectCount(new LambdaQueryWrapper<UserPaidAlbum>()
                .eq(UserPaidAlbum::getUserId, userId).eq(UserPaidAlbum::getAlbumId, albumId)) == 1;

    }

    /**
     * 查询用户购买的声音id
     *
     * @param userId
     * @param albumId
     * @return
     */
    @Override
    public Map<String, Integer> getBuyTrackList(Long userId, Long albumId) {
        return userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>()
                .eq(UserPaidTrack::getUserId, userId).eq(UserPaidTrack::getAlbumId, albumId))
                .stream().collect(Collectors.toMap(key->key.getTrackId().toString(),value->1));
    }
}
